1 : <?php
2 : /*--------------------------------------------------------------------------+
3 : This file is part of eStudy.
4 : common/classes/class.email.inc.php
5 : - Modulgruppe: Framework
6 : - Beschreibung: Klasse zur Kapselung von Email-Funktionalität.
7 : - Version: 0.1.3, 04/04/04
8 : - Autor(en): Christian Gerhardt <case42@gmx.net>
9 : +---------------------------------------------------------------------------+
10 : This program is free software; you can redistribute it and/or
11 : modify it under the terms of the GNU General Public License
12 : as published by the Free Software Foundation; either version 2
13 : of the License, or any later version.
14 : +---------------------------------------------------------------------------+
15 : This program is distributed in the hope that it will be useful,
16 : but WITHOUT ANY WARRANTY; without even the implied warranty of
17 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 : GNU General Public License for more details.
19 : You should have received a copy of the GNU General Public License
20 : along with this program; if not, write to the Free Software
21 : Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 : +--------------------------------------------------------------------------*/
23 :
24 : require_once (PATH_TO_ROOT."common/classes/class.certificate.inc.php");
25 :
26 : /**
27 : * In dieser Datei befindet sich die Implementierung der Klasse Email.
28 : * @package eStudy.Framework
29 : * @subpackage Mailsystem
30 : * @author Christian Gerhardt <case42@gmx.net>
31 : * @version 0.1.4, 03/09/04
32 : */
33 : /**
34 : * Klasse zum Versenden von Emails mit dem eStudy-Portal.
35 : * Diese Klasse stellt eine Reihe von Funktionalitäten bereit die im Umgang mit
36 : * Emails hilfreich sein können.<br>
37 : * Der gesammte Emailverkehr des eStudy-Prtals soll mit Hilfe dieser Klasse
38 : * zentralisiert, um eine geringe Kopplung unter den einzelnen eStudy-Komponenten
39 : * zu erreichen und die mehrfach Generierung von Code zu verhindern<br>
40 : * Die beiden Methoden {@link validate() <b>validate()</b>} und
41 : * {@link sendMessageToAddressFromNotUser() <b>sendMessageToAddressFromNotUser()</b>}
42 : * können entsprechend auch ohne das zugehörige Objekt benutzt werden.<br>
43 : * @author Christian Gerhardt <case42@gmx.net>
44 : * @version 0.1.3, 04/04/04
45 : * @package eStudy.Framework
46 : * @subpackage Mailsystem
47 : * @copyright 2003
48 : *
49 : */
50 : class Email {
51 : /**
52 : * In welchem Format die Email abgeschickt werden soll.
53 : * Gültig sind <i>html</i> und <i>txt</i>.
54 : * @access protected
55 : * @var string
56 : */
57 : var $contentType;
58 : /**
59 : * Die ID des aktuellen Benutzers .
60 : * @access protected
61 : * @var integer
62 : */
63 : var $userID;
64 : /**
65 : * Die Emailadresse des Benutzers.
66 : * @access protected
67 : * @var string
68 : */
69 : var $email;
70 : /**
71 : * Der Name des Benutzers.
72 : * @access protected
73 : * @var string
74 : */
75 : var $name;
76 : /**
77 : * Buffer für bereits aus der Datenbank geholten Emailadressen.
78 : * @access private
79 : * @var array
80 : */
81 : var $userMails;
82 : /**
83 : * Ob die Signatur des Portals an Emails angehängt werden soll
84 : * @access private
85 : * @var bool
86 : */
87 : var $sendSignature = true;
88 :
89 : /**
90 : * Kontruktur für Email-Objekte.
91 : * Dieser Kontruktor benötigt die ID des aktuellen Users des Portals und
92 : * holt sich mit deren Hilfe seine Email-Adresse aus der Datenbank.<br>
93 : * Sollte bei diesem Vorgang ein Fehler auftreten, wird die userID auf 0 gesetzt
94 : * und seine Emailadresse bekommt den bool'schen Wert <i>false</i>.<br>
95 : * Dies sollte aber bei korrekter Anwendung der Klasse und des Portals nicht
96 : * vorkommen.<br>
97 : * @access public
98 : * @param integer $userID - Die ID des aktuellen Users
99 : */
100 : function Email($userID) {
101 0 : global $db;
102 0 : $this->contentType = 'txt';
103 0 : if (is_numeric($userID)) {
104 0 : $this->userID = $userID;
105 0 : $results = $db->get_row("SELECT Nachname, Vorname, Email, useSecureEmail from user WHERE ID='$userID'");
106 0 : $this->email = $results->Email;
107 0 : $this->name = $results->Vorname." ".$results->Nachname;
108 0 : } else {
109 : //falsche parameterübergabe : mit standardwerten füllen
110 0 : $this->userID = 0;
111 0 : $this->email = false;
112 : }
113 0 : }
114 : /**
115 : * Sendet eine Nachricht an einen User oder mehrere User des Portals.
116 : * Wenn $single = <i>TRUE</i> wird an jeden User eine einzelne Email versendet, falls
117 : * <i>FALSE</i> wird eine Sammelmail an alle versendet.
118 : * @access public
119 : * @param string $subject - der Betreff
120 : * @param mixed $to - ein Empfänger-UserID(integer) oder mehrere (array aus integern)
121 : * @param string $message - die Nachricht
122 : * @param bool $single - ob an jeden User eine einzelne Mail versendet werden soll, oder eine Sammelmail an alle gleichzeitig
123 : * @return bool - Erfolgswert
124 : */
125 : function sendMessageToUser($subject, $to, $message, $single = false) {
126 : // die benutzerdaten überprüfen!
127 0 : if ($this->userID === 0 || $this->email === false) return false;
128 : // überprüfen ob ein gültiger Empfänger eingetragen wurde
129 0 : if (is_array($to)) {
130 0 : $addresses = array();
131 0 : if (count($to) > 0) {
132 0 : foreach($to as $t) {
133 0 : $address = $this->getUserEmailAddress($t);
134 0 : if (!empty($address)) {
135 0 : if ($this->secureEmailAvailable($t))
136 0 : $this->sendSecureMessageToUser($subject, $t, $message);
137 : else
138 0 : $addresses[] = $address;
139 0 : }
140 0 : }
141 0 : if ($single) $address = implode(",", $addresses);
142 0 : else $address = $addresses;
143 0 : } else {
144 0 : return false;
145 : }
146 0 : } else {
147 0 : $address = $this->getUserEmailAddress($to);
148 0 : if ($address === false) return false;
149 0 : if ($this->secureEmailAvailable($t))
150 0 : return $this->sendSecureMessageToUser($subject, $t, $message);
151 : }
152 0 : $data['from'] = $this->name." <".$this->email.">";
153 0 : $data['to'] = $address;
154 0 : $data['subject'] = $subject;
155 0 : $data['message'] = $message;
156 0 : return $this->send($data);
157 : }
158 : /**
159 : * Sendet eine Nachricht an eine Externe Adresse.
160 : * Auch mehrer Empfänger sind möglich.
161 : * Wenn $single = <i>TRUE</i> wird an jeden User eine einzelne Email versendet, falls
162 : * <i>FALSE</i> wird eine Sammelmail an alle versendet.
163 : * @access public
164 : * @param string $subject - der Betreff
165 : * @param mixed $to - eine Empfängeradresse(string) oder mehrere (array)
166 : * @param string $message - Die Nachricht
167 : * @param bool $single - ob an jeden User eine einzelne Mail versendet werden soll, oder eine Sammelmail an alle gleichzeitig
168 : * @return bool - Erfolgswert
169 : */
170 : function sendMessageToAddress($subject, $to, $message, $single = false) {
171 : //überprüfen ob Emailadressen übergeben wurden
172 0 : if (is_array($to)) {
173 0 : if (count($to) > 0) {
174 0 : foreach($to as $t) {
175 0 : if (!$this->validate($t)) return false;
176 0 : }
177 0 : if ($single) $to = implode(",", $to);
178 0 : } else {
179 0 : return false;
180 : }
181 0 : } else {
182 0 : if (!$this->validate($to)) return false;
183 : }
184 0 : $data['from'] = $this->name." <".$this->email.">";
185 0 : $data['to'] = $to;
186 0 : $data['subject'] = $subject;
187 0 : $data['message'] = $message;
188 0 : return $this->send($data);
189 : }
190 : /**
191 : * Sendet eine Nachticht von einem Nicht-Portalbenutzer an eine externe Adresse.
192 : * Auch mehere Empfänger sind möglich.
193 : * Wenn $single = <i>TRUE</i> wird an jeden User eine einzelne Email versendet, falls
194 : * <i>FALSE</i> wird eine Sammelmail an alle versendet.
195 : * @access public
196 : * @static
197 : * @param string $from - Absenderadresse
198 : * @param string $subject - der Betreff
199 : * @param mixed $to - eine Empfängeradresse(string) oder mehrere (array)
200 : * @param string $message - die Nachricht
201 : * @param bool $single - ob an jeden User eine einzelne Mail versendet werden soll, oder eine Sammelmail an alle gleichzeitig
202 : * @return bool - Erfolgswert
203 : */
204 : function sendMessageToAddressFromNotUser($subject, $from, $to, $message, $single = false) {
205 : //überprüfen ob Emailadressen übergeben wurden
206 0 : if (!Email::validate($from)) return false;
207 0 : if (is_array($to)) {
208 0 : if (count($to) > 0) {
209 0 : foreach($to as $t) {
210 0 : if (!Email::validate($t)) return false;
211 0 : }
212 0 : if ($single) $to = implode(",", $to);
213 0 : } else {
214 0 : return false;
215 : }
216 0 : } else {
217 0 : if (!Email::validate($to)) return false;
218 : }
219 0 : $data['from'] = $from;
220 0 : $data['to'] = $to;
221 0 : $data['subject'] = $subject;
222 0 : $data['message'] = $message;
223 0 : return Email::send($data);
224 : }
225 : /**
226 : * Überprüft E-Mail-Adressen auf Richtigkeit.
227 : * Übergebene E-Mail-Adresse wird auf Übereinstimmung mit dem
228 : * in der RFC819-Spezifikation beschriebenen Aufbau einer
229 : * Internet-Mailbox-Adresse überprüft.
230 : *
231 : * @access public
232 : * @static
233 : * @author Timo Fuchs <timo.fuchs@mni.fh-giessen.de>
234 : * @version 1.0, 09/11/03
235 : *
236 : * @param string $address - Die zu überprüfende E-Mail-Adresse.
237 : * @return bool - true, falls Adresse richtigen Aufbau hat;
238 : * false, falls nicht.
239 : */
240 : function validate($address) {
241 0 : if (is_string($address)) {
242 : // Beschreibt ein Zeichen, das nicht im ASCIIzeichensatz enthalten ist.
243 0 : $nonascii = "\x80-\xff";
244 : // Beschreibt ein Zeichen, das nicht geqoutet werden muss.
245 0 : $nqtext = "[^\\\\$nonascii\015\012\]";
246 : // Beschreibt ein Zeichen, das gequotet werden muss.
247 0 : $qchar = "\\\\[^$nonascii]";
248 : // Beschreibt den String "mailto:".
249 0 : $protocol = '(?:mailto:)';
250 : //--BEGIN Benutzername-----------------------------------------------
251 : // Bechreibt einen normalen Benutzernamen.
252 0 : $normuser = '[a-zA-Z0-9][a-zA-Z0-9_.-]*';
253 : // Beschreibt einen Benutzernamen in Anfuehrungszeichen.
254 0 : $quotedstring = "\"(?:$nqtext|$qchar)+\"";
255 : // Beschreibt den Aufbau eines Benutzernamens.
256 0 : $user_part = "(?:$normuser|$quotedstring)";
257 : //--END Benutzername------------------------------------------------
258 : //--Begin Domain----------------------------------------------------
259 : // Beschreibt einen Domain-Teil.
260 0 : $dom_mainpart = '[a-zA-Z0-9][a-zA-Z0-9._-]*\\.';
261 : // Beschreibt einen Subdomain-Teil, 0-n Subdomains.
262 0 : $dom_subpart = '(?:[a-zA-Z0-9][a-zA-Z0-9._-]*\\.)*';
263 : // Beschreibt eine Toplevel-Domain.
264 0 : $dom_tldpart = '[a-zA-Z]{2,5}';
265 : // Beschreibt den Aufbau einer Domain.
266 0 : $domain_part = "$dom_subpart$dom_mainpart$dom_tldpart";
267 : //--END Domain-------------------------------------------------------
268 : // Beschreibt den Aufbau einer E-Mail-Adresse.
269 0 : $regex = "$protocol?$user_part\@$domain_part";
270 0 : return preg_match("/^$regex$/", $address);
271 : } else {
272 0 : return false;
273 : }
274 : }
275 : /**
276 : * Versendet Emails.
277 : * Diese Methode stellt die flexibelsten Weg dar und es gibt eigentlich keinen
278 : * Grund warum man die in PHP bereits eingebaute <i>mail()</i> Funktion
279 : * nicht dieser vorziehen sollte. Der einzige Grund ist die Zentralisierung
280 : * und die dadurch erreichte Entkoppeltung zwischen den einzelnen Elementen.
281 : * Jedewede Versendung von Emails soll über diese Klasse gehen und dem entsprechend
282 : * muß es diese Methode geben, um die Möglichkeiten der <i>mail()</i> Funktion
283 : * abzubilden.<br>
284 : * Die Datenstruktur als Parameter sieht folgenermaßen aus:<br>
285 : * $data['to'] - Empfängeradresse<br>
286 : * $data['subject'] - Betreff<br>
287 : * $data['message'] - Die Nachricht<br>
288 : * $data['from'] - Die Absender-adresse (Wird in den Header eingbaut)
289 : * $data['header'] - Der Header der übergeben werden soll.<br>
290 : * @access public
291 : * @static
292 : * @param array $data - Eine Datenstruktur für die Daten der E-Mail
293 : * @return bool - Erfolgswert
294 : */
295 : function send($data) {
296 0 : global $db, $settings;
297 0 : if (!is_array($data)) return false;
298 : // Prüfen, ob überhaupt E-Mails verschickt werden dürfen
299 0 : if (!$settings["send_emails"] || (!COMMON_MODULE && !$db->get_var("SELECT mailflag FROM modulegroups JOIN modules ON modulegroups.ID=modules.modulegroupsID WHERE Script='".SCRIPT_NAME."'"))) return false;
300 : //signatur anhängen
301 0 : if ($this->sendSignature) $data['message'].= $this->getSignature();
302 : //ansender einstellen
303 0 : $header = "From: ".$data['from']."\n";
304 0 : $header.= "Mime-Version: 1.0\n";
305 0 : $header.= "X-Mailer: eStudy ".ESTUDY_VERSION."\n";
306 : //inhaltstyp einstellen
307 0 : $data['subject'] = html_entity_decode($data['subject']);
308 0 : if ($this->contentType == 'html') {
309 0 : $boundary = md5($data['subject'].$data['message'].time());
310 0 : $origMessage = $data['message'];
311 0 : $data['message'] = "--$boundary\n"."Content-Type: text/plain; charset=".$settings["charset"]."\n\n".html_entity_decode(strip_tags(str_replace(array("<br>", "<br />", "<br/>", "<p>", "</p>", "<tr>", "<li>", "<ol>", "<ul>"), "\n", str_replace(array("\n", "\r"), "", $origMessage))), ENT_COMPAT, $settings["charset"]) ."\n"."--$boundary\n"."Content-Type: text/html; charset=".$settings["charset"]."\n\n"."<html>\n<head><title>".Data::toHTML($data['subject']) ."</title></head>\n<body>$origMessage</body>\n</html>\n"."--$boundary--\n";
312 0 : $header.= "Content-Type: multipart/alternative; boundary=$boundary\n";
313 0 : } else {
314 0 : $header.= "Content-Type: text/plain; charset=".$settings["charset"]."\n";
315 : // Einfache Anführungszeichen werden aus irgendeinem Grund immer als Entity dargestellt
316 0 : $data['message'] = str_replace("'", "'", $data['message']);
317 : }
318 0 : if (is_array($data['to'])) {
319 0 : $ok = true;
320 0 : foreach($data['to'] as $to) {
321 0 : $result = @mail($to, $data['subject'], $data['message'], $header, $settings["mta_params"]);
322 0 : if (!$result) $ok = false;
323 0 : }
324 0 : return $ok;
325 : }
326 0 : return @mail($data['to'], $data['subject'], $data['message'], $header, $settings["mta_params"]);
327 : }
328 :
329 : /**
330 : * Prüft, ob verschlüsselte Email ferfügbar
331 : * @return boolean
332 : */
333 : private function secureEmailAvailable( $userID ) {
334 0 : global $db;
335 0 : $useSecureEmail = $db->get_results("SELECT useSecureEmail FROM user WHERE ID='$userID' OR ID='$this->userID'");
336 0 : $fromCert = new Certificate( $this->userID );
337 0 : $toCert = new Certificate( $userID );
338 :
339 0 : if (($fromCert->getCertInfo()) && ($toCert->getCertInfo()) && ($useSecureEmail[0]->useSecureEmail) && ($useSecureEmail[1]->useSecureEmail)) return true;
340 0 : return false;
341 : }
342 :
343 : /**
344 : * Holt die Emailadresse eines Users aus der Datenbank
345 : * @access public
346 : * @param integer $userID - Die ID des Users
347 : * @return string - die Emailadresse oder false
348 : */
349 : function getUserEmailAddress($userID) {
350 0 : global $db;
351 0 : if (!isset($db)) return false; //datenbank nicht gesetzt;
352 0 : if (is_numeric($userID)) {
353 0 : if (isset($this->userMails[$userID])) return $this->userMails[$userID];
354 0 : $email = $db->get_var("SELECT Email FROM user WHERE ID='$userID'");
355 0 : if ($email) {
356 0 : $this->userMails[$userID] = $email;
357 0 : return $email;
358 : }
359 0 : }
360 0 : return false;
361 : }
362 : /**
363 : * Stellt ein ob an eine Email die Signatur des Portals angehängt werden soll.
364 : * @access public
365 : * @param bool $how - Ob die Signature gesendet werden soll(=true) oder nicht(=false).
366 : * @return void
367 : */
368 : function sendSignature($how) {
369 0 : if (is_bool($how)) $this->sendSignature = $how;
370 0 : }
371 : /**
372 : * Setzt das Format der Email auf einen neuen Typ.
373 : * @access public
374 : * @var string $how - <i>txt</i> oder <i>html</i>
375 : * @return void
376 : */
377 : function setContentType($how) {
378 0 : $how = strtolower($how);
379 0 : if ($how == 'txt' or $how == 'html') $this->contentType = $how;
380 0 : }
381 : /**
382 : * Gibt die Signatur des Portals in einem String zurück
383 : * @access public
384 : * @return string
385 : */
386 : function getSignature() {
387 0 : global $settings;
388 0 : if ($this->contentType == 'html') {
389 0 : $signature = "<p>\n";
390 0 : $signature.= "<hr />\n";
391 0 : $signature.= "eStudy-Portal<br />\n";
392 0 : $signature.= "Version: ".ESTUDY_VERSION."<br />\n";
393 0 : $signature.= str_replace(array('\n', '\r', '\t'), array(chr(10), chr(13), chr(9)), stripslashes($settings["email_signature_html"])) ."</p>";
394 0 : } else {
395 0 : $signature = "\n\n\n----------------------------\n";
396 0 : $signature.= "eStudy-Portal\n";
397 0 : $signature.= "Version: ".ESTUDY_VERSION."\n";
398 0 : $signature.= str_replace(array('\n', '\r', '\t'), array(chr(10), chr(13), chr(9)), stripslashes($settings["email_signature_text"]));
399 : }
400 0 : return $signature;
401 : }
402 :
403 : /**
404 : * Versendet verschlüsselt und signierte Emails.
405 : * Die Datenstruktur als Parameter sieht folgenermaßen aus:<br>
406 : * $data['to'] - Empfängeradresse<br>
407 : * $data['subject'] - Betreff<br>
408 : * $data['message'] - Die Nachricht<br>
409 : * $data['from'] - Die Absender-adresse (Wird in den Header eingbaut)
410 : * $data['header'] - Der Header der übergeben werden soll.<br>
411 : * @author Tobias Wolf <tobias.wolf@mni.fh-giessen.de>
412 : * @version 1.0, 30/07/08
413 : * @access public
414 : * @static
415 : * @param array $data - Eine Datenstruktur für die Daten der E-Mail
416 : * @return bool - Erfolgswert
417 : */
418 : function sendSecure($data) {
419 0 : global $db, $settings;
420 :
421 0 : if (!is_array($data)) return false;
422 : // Prüfen, ob überhaupt E-Mails verschickt werden dürfen
423 0 : if (!$settings["send_emails"] || (!COMMON_MODULE && !$db->get_var("SELECT mailflag FROM modulegroups JOIN modules ON modulegroups.ID=modules.modulegroupsID WHERE Script='".SCRIPT_NAME."'"))) return false;
424 :
425 : //inhaltstyp einstellen
426 0 : $data['subject'] = html_entity_decode($data['subject']);
427 0 : if ($this->contentType == 'html') {
428 0 : $boundary = md5($data['subject'].$data['message'].time());
429 0 : $origMessage = $data['message'];
430 0 : $data['message'] = "--$boundary\n"."Content-Type: text/plain; charset=".$settings["charset"]."\n\n".html_entity_decode(strip_tags(str_replace(array("<br>", "<br />", "<br/>", "<p>", "</p>", "<tr>", "<li>", "<ol>", "<ul>"), "\n", str_replace(array("\n", "\r"), "", $origMessage))), ENT_COMPAT, $settings["charset"]) ."\n"."--$boundary\n"."Content-Type: text/html; charset=".$settings["charset"]."\n\n"."<html>\n<head><title>".Data::toHTML($data['subject']) ."</title></head>\n<body>$origMessage</body>\n</html>\n"."--$boundary--\n";
431 0 : $header.= "Content-Type: multipart/alternative; boundary=$boundary\n";
432 0 : } else {
433 : //$header.= "Content-Type: text/plain; charset=".$settings["charset"]."\n";
434 : // Einfache Anführungszeichen werden aus irgendeinem Grund immer als Entity dargestellt
435 0 : $data['message'] = str_replace("'", "'", $data['message']);
436 : }
437 0 : if (is_array($data['to'])) {
438 0 : $ok = true;
439 0 : foreach($data['to'] as $to) {
440 0 : $result = @mail($to, $data['subject'], $data['message'], $header, $settings["mta_params"]);
441 0 : if (!$result) $ok = false;
442 0 : }
443 0 : return $ok;
444 : }
445 :
446 0 : return mail($data['to'], $data['subject'], $data['message'], $data['header'], $settings["mta_params"]);
447 : }
448 :
449 : /**
450 : * Sendet verschlüsselt und signierte Nachrichten an einen User oder mehrere User des Portals.
451 : * @author Tobias Wolf <tobias.wolf@mni.fh-giessen.de>
452 : * @version 1.0, 30/07/08
453 : * @access public
454 : * @param string $subject - der Betreff
455 : * @param mixed $to - ein Empfänger-UserID(integer)
456 : * @param string $message - die Nachricht
457 : * @return bool - Erfolgswert
458 : */
459 : function sendSecureMessageToUser($subject, $to, $message) {
460 : // die benutzerdaten überprüfen!
461 0 : if ($this->userID === 0 || $this->email === false) return false;
462 :
463 0 : $address = $this->getUserEmailAddress($to);
464 0 : if ($address === false) return false;
465 0 : $data['fromId'] = $this->userID;
466 0 : $data['from'] = $this->name." <".$this->email.">";
467 0 : $data['to'] = $address;
468 0 : $data['subject'] = utf8_decode($subject);
469 0 : $data['message'] = utf8_decode($message);
470 :
471 0 : $md = new Certificate($to);
472 0 : if($md->getCertInfo() == false) return false;
473 :
474 0 : $mailparts = $md->makeEmailMessage($data);
475 :
476 0 : $data['message'] = $mailparts[1];
477 0 : $data['header'] = $mailparts[0];
478 :
479 0 : return $this->sendSecure($data);
480 : }
481 : }
|